<template>
  <div class="rich-value-display">
    <!-- Check for circular reference first -->
    <span v-if="isCircular" class="value-circular">[Circular]</span>
    
    <!-- Check depth limit next -->
    <span v-else-if="depth >= maxDepth" class="value-max-depth">[Max Depth Reached]</span>
    
    <!-- Existing rendering logic wrapped in v-else -->
    <template v-else>
      <!-- Handle basic types -->
      <span v-if="value === null" class="value-null">null</span>
      <span v-else-if="value === undefined" class="value-undefined">undefined</span>
      <span v-else-if="typeof value === 'string'" class="value-string">"{{ value }}"</span>
      <span v-else-if="typeof value === 'number'" class="value-number">{{ value }}</span>
      <span v-else-if="typeof value === 'boolean'" :class="['value-boolean', value ? 'is-true' : 'is-false']">{{ value }}</span>
      <span v-else-if="typeof value === 'bigint'" class="value-bigint">{{ value }}n</span>
      <span v-else-if="typeof value === 'symbol'" class="value-symbol">{{ value.toString() }}</span>

      <!-- Handle Date -->
      <span v-else-if="value instanceof Date" class="value-date" :title="value.toISOString()">
        <el-icon><Calendar /></el-icon> {{ formatDateTime(value) }}
      </span>

      <!-- Handle RegExp -->
      <span v-else-if="value instanceof RegExp" class="value-regexp">
        {{ value.toString() }}
      </span>

      <!-- Handle Errors (including deserialized execution errors) -->
      <div v-else-if="isError" class="error-value standard-error">
        <span class="type-indicator error">[Error]</span>
        <span class="error-name">{{ value.name }}:</span>
        <span class="error-message">{{ value.message }}</span>
        <pre v-if="value.stack" class="error-stack">{{ value.stack }}</pre>
        <!-- Use computed property for cause display -->
        <div v-if="showErrorCause" class="error-cause">
          <span class="cause-label">Caused by:</span>
          <RichValueDisplay
            :key="path ? `${path}.cause` : 'cause'"
            :value="value.cause"
            :depth="depth + 1"
            :max-depth="maxDepth"
            :path="path ? `${path}.cause` : 'cause'"
          />
        </div>
        <span v-else-if="value.cause && depth >= maxDepth" class="depth-limit">(Max depth reached for cause)</span>
      </div>

      <!-- Handle Function Marker -->
      <div v-else-if="value?.__universalType__ === 'Function'" class="value-function">
         <span class="function-tag">[Function{{ functionName ? ': ' + functionName : '' }}]</span>
         <el-collapse v-model="activeFunctionCollapse" accordion v-if="value.source" class="function-source-collapse">
             <el-collapse-item title="View Source" name="1">
                 <pre class="function-source">{{ value.source }}</pre>
             </el-collapse-item>
         </el-collapse>
      </div>

      <!-- Handle Map -->
      <div v-else-if="value instanceof Map" class="value-map">
        <span class="collection-summary">Map ({{ value.size }} entries)</span>
        <el-collapse v-model="activeMapCollapse" accordion v-if="value.size > 0" class="collection-collapse">
          <el-collapse-item title="View Entries" name="1">
            <div v-for="([mapKey, mapValue], index) in limitedMapEntries" :key="index" class="map-entry">
              <RichValueDisplay :value="mapKey" :path="`${path}.keys[${index}]`" :depth="depth + 1" :visited="new Set(visited).add(value)" class="map-key" />
              <span class="map-separator">:</span>
              <RichValueDisplay :value="mapValue" :path="`${path}.values[${index}]`" :depth="depth + 1" :visited="new Set(visited).add(value)" class="map-value" />
            </div>
            <div v-if="value.size > displayLimit" class="limit-indicator">... ({{ value.size - displayLimit }} more entries)</div>
          </el-collapse-item>
        </el-collapse>
      </div>

      <!-- Handle Set -->
      <div v-else-if="value instanceof Set" class="value-set">
         <span class="collection-summary">Set ({{ value.size }} values)</span>
         <el-collapse v-model="activeSetCollapse" accordion v-if="value.size > 0" class="collection-collapse">
           <el-collapse-item title="View Values" name="1">
             <div v-for="(setValue, index) in limitedSetValues" :key="index" class="set-value">
               <RichValueDisplay :value="setValue" :path="`${path}[${index}]`" :depth="depth + 1" :visited="new Set(visited).add(value)" />
             </div>
             <div v-if="value.size > displayLimit" class="limit-indicator">... ({{ value.size - displayLimit }} more values)</div>
           </el-collapse-item>
         </el-collapse>
      </div>

      <!-- Handle Array -->
      <div v-else-if="Array.isArray(value)" class="value-array">
        <span class="collection-summary">Array ({{ value.length }} items)</span>
        <el-collapse v-model="activeArrayCollapse" accordion v-if="value.length > 0" class="collection-collapse">
          <el-collapse-item title="View Items" name="1">
            <div v-for="(item, index) in limitedArrayItems" :key="index" class="array-item">
              <span class="array-index">{{ index }}:</span>
              <RichValueDisplay :value="item" :path="`${path}[${index}]`" :depth="depth + 1" :visited="new Set(visited).add(value)" class="array-value"/>
            </div>
            <div v-if="value.length > displayLimit" class="limit-indicator">... ({{ value.length - displayLimit }} more items)</div>
          </el-collapse-item>
        </el-collapse>
      </div>

      <!-- Handle Plain Object -->
       <div v-else-if="isPlainObject(value)" class="value-object">
         <span class="collection-summary">Object ({{ objectKeys.length }} keys)</span>
         <el-collapse v-model="activeObjectCollapse" accordion v-if="objectKeys.length > 0" class="collection-collapse">
           <el-collapse-item title="View Properties" name="1">
             <div v-for="(key, index) in limitedObjectKeys" :key="index" class="object-entry">
               <span class="object-key">{{ formatObjectKey(key) }}:</span>
               <RichValueDisplay :value="value[key]" :path="`${path}.${String(key)}`" :depth="depth + 1" :visited="new Set(visited).add(value)" class="object-value"/>
             </div>
             <div v-if="objectKeys.length > displayLimit" class="limit-indicator">... ({{ objectKeys.length - displayLimit }} more properties)</div>
           </el-collapse-item>
         </el-collapse>
       </div>

      <!-- --- Use computed property for ArrayBuffer check --- -->
      <div v-else-if="isArrayBuffer" class="value-binary value-arraybuffer">
        <span class="binary-type">ArrayBuffer</span>
        <span class="binary-size">({{ value.byteLength }} bytes)</span>
      </div>

      <!-- --- Use computed property for TypedArray check --- -->
      <div v-else-if="isTypedArray" class="value-binary value-typedarray">
        <span class="binary-type">{{ getConstructorName(value) }}</span>
        <span class="binary-size">({{ value.byteLength }} bytes)</span>
        <span class="binary-preview" v-if="value.byteLength > 0">
          [<span v-for="(byte, index) in typedArrayPreview" :key="index">{{ byte }}{{ index < typedArrayPreview.length - 1 ? ', ' : '' }}</span>{{ value.length > previewByteLimit ? ', ...' : '' }}]
        </span>
      </div>
      
      <!-- --- Use computed property for DataView check --- -->
       <div v-else-if="isDataView" class="value-binary value-dataview">
          <span class="binary-type">DataView</span>
          <span class="binary-size">({{ value.byteLength }} bytes)</span>
       </div>

      <!-- 2. Handle special error markers (deserialization/execution errors) -->
      <div v-else-if="value && (value.__universalError__ || value.__universalExecutionError__)" class="value-error special-error">
        <el-alert type="error" :closable="false" :title="errorTitle">
          <p>{{ errorMessage }}</p>
          <pre v-if="errorStack" class="error-stack">{{ errorStack }}</pre>
          <!-- Cause display might not be applicable/standardized for these markers -->
        </el-alert>
      </div>

      <!-- Fallback for other complex types -->
      <span v-else class="value-unknown">[Unknown Type: {{ getConstructorName(value) }}]</span>
    </template>

  </div>
</template>

<script setup lang="ts">
import { ref, computed, defineAsyncComponent, watchEffect } from 'vue';
import { isPlainObject } from 'lodash-es'; // Use lodash helper
import { ElCollapse, ElCollapseItem, ElIcon, ElAlert, ElTooltip } from 'element-plus';
import { Calendar, InfoFilled, CaretRight } from '@element-plus/icons-vue';
// --- IMPORT Settings Store ---
import { useUniversalVisualizerSettingsStore } from '@/stores/universalVisualizerSettingsStore';
import type {
    UniversalFunctionIR
} from '@/models/universalTransferTypes';

// Define props
interface Props {
  value: any;
  path?: string;  // Optional path for context
  depth?: number; // Optional depth for controlling expansion/limits
  visited?: Set<any>; // Keep track of objects visited in this rendering path
  maxDepth?: number;
  itemLimit?: number;
}

const props = withDefaults(defineProps<Props>(), {
  path: 'root',
  depth: 0,
  visited: () => new Set<any>(),
  maxDepth: 10,
  itemLimit: 10,
});

// --- Use Settings Store --- 
const settings = useUniversalVisualizerSettingsStore();
// Get reactive references to the settings
const displayLimit = computed(() => props.itemLimit ?? settings.richDisplayItemLimit);
const maxDepth = computed(() => props.maxDepth ?? settings.richDisplayMaxDepth);

// --- Define the recursive component explicitly for use in template ---
// This is needed because <script setup> doesn't easily allow self-reference in template
const RichValueDisplay = defineAsyncComponent(() => import('./RichValueDisplay.vue'));

// Active collapse states
const activeFunctionCollapse = ref<string | string[]>('');
const activeMapCollapse = ref<string | string[]>('');
const activeSetCollapse = ref<string | string[]>('');
const activeArrayCollapse = ref<string | string[]>('');
const activeObjectCollapse = ref<string | string[]>('');

// Computed properties for limited display
const limitedMapEntries = computed(() => {
  if (props.value instanceof Map) {
    return Array.from(props.value.entries()).slice(0, displayLimit.value);
  }
  return [];
});

const limitedSetValues = computed(() => {
  if (props.value instanceof Set) {
    return Array.from(props.value.values()).slice(0, displayLimit.value);
  }
  return [];
});

const limitedArrayItems = computed(() => {
  if (Array.isArray(props.value)) {
    return props.value.slice(0, displayLimit.value);
  }
  return [];
});

const objectKeys = computed(() => {
    if (isPlainObject(props.value)) {
        // Get both string and symbol keys
        return Reflect.ownKeys(props.value);
    }
    return [];
});

const limitedObjectKeys = computed(() => {
  return objectKeys.value.slice(0, displayLimit.value);
});

const formatObjectKey = (key: string | symbol): string => {
    return typeof key === 'symbol' ? key.toString() : key;
};

// --- ADD Check for circular reference before rendering complex types ---
const isCircular = computed(() => {
    if (props.value !== null && (typeof props.value === 'object' || typeof props.value === 'function')) {
        return props.visited?.has(props.value);
    }
    return false;
});

// --- Computed check if rendering should stop due to depth or circularity ---
const stopRendering = computed(() => props.depth >= maxDepth.value || isCircular.value);

// --- NEW: Computed properties for type checking in template ---
const isArrayBuffer = computed(() => props.value instanceof ArrayBuffer);
const isTypedArray = computed(() => ArrayBuffer.isView(props.value) && !(props.value instanceof DataView));
const isDataView = computed(() => props.value instanceof DataView);

// Helper to format Date
const formatDateTime = (date: Date): string => {
  try {
    // Use Intl for locale-aware formatting if possible, fallback to ISO
    if (typeof Intl !== 'undefined' && typeof Intl.DateTimeFormat === 'function') {
      return new Intl.DateTimeFormat(undefined, { dateStyle: 'medium', timeStyle: 'medium' }).format(date);
    }
    return date.toISOString();
  } catch {
    return '[Invalid Date]';
  }
};

// Helper for function name extraction
const functionName = computed(() => {
    if (props.value?.__universalType__ === 'Function' && props.value.source) {
        const match = props.value.source.match(/^(?:async\s+)?function\*?\s+([a-zA-Z0-9_$]+)\s*\(/);
        return match ? match[1] : '';
    }
    return '';
});

// Computed properties for the special error block (using ElAlert)
const errorTitle = computed(() => {
  if (!props.value) return 'Error';
  if (props.value.__universalExecutionError__) return props.value.__universalExecutionError__.name || 'Execution Error';
  if (props.value.__universalError__) return 'Deserialization Error';
  // This case should ideally not be hit if isError branch works
  if (props.value instanceof Error) return props.value.name || 'Error'; 
  return 'Unknown Error';
});

const errorMessage = computed(() => {
  if (!props.value) return 'Unknown error occurred.';
  if (props.value.__universalExecutionError__) return props.value.__universalExecutionError__.message || '';
  if (props.value.__universalError__) return String(props.value.__universalError__);
  // This case should ideally not be hit
  if (props.value instanceof Error) return props.value.message || '';
  return String(props.value);
});

const errorStack = computed(() => {
  if (!props.value) return null;
  if (props.value.__universalExecutionError__) return props.value.__universalExecutionError__.stack;
  // Standard Error stack handled in the first block
  return null; 
});

// Helper to get constructor name for fallback
const getConstructorName = (obj: any): string => {
  if (obj && obj.constructor && obj.constructor.name) {
    return obj.constructor.name;
  }
  return 'Object';
};

// --- ADD constant for preview limit ---
const previewByteLimit = 16; // Show max 16 bytes in preview

// --- ADD computed property for TypedArray preview ---
const typedArrayPreview = computed(() => {
  if (ArrayBuffer.isView(props.value) && !(props.value instanceof DataView)) {
    // Create a Uint8Array view for consistent byte access, regardless of original type
    const uint8View = new Uint8Array(props.value.buffer, props.value.byteOffset, props.value.byteLength);
    // Slice to get the preview bytes
    const previewBytes = Array.from(uint8View.slice(0, previewByteLimit));
    return previewBytes;
  }
  return [];
});

const isFunctionMarker = computed(() => 
    props.value && typeof props.value === 'object' && props.value.__universalType__ === 'Function'
);
const isRegExp = computed(() => props.value instanceof RegExp);

// RE-ADD watchEffect
watchEffect(() => {
  if (props.value instanceof Error) {
    console.log(`[RichValueDisplay] Received Error prop for path '${props.path}'. Value:`, props.value);
    console.log(`  > Has 'cause' property:`, 'cause' in props.value);
    console.log(`  > Cause value:`, props.value.cause);
  }
});

// ADD computed property for showing the cause (used in standard Error block)
const showErrorCause = computed(() => {
  const shouldShow = Boolean(
    props.value instanceof Error && 
    props.value.cause && 
    props.depth < maxDepth.value
  );
  // console.log(`[RichValueDisplay Computed] showErrorCause for path '${props.path}':`, shouldShow); // Keep log for now
  return shouldShow;
});

const isError = computed(() => props.value instanceof Error);

</script>

<style lang="scss" scoped>
.rich-value-display {
  font-family: monospace;
  font-size: 0.95em;
  line-height: 1.5;
}

.value-null,
.value-undefined {
  color: var(--el-text-color-secondary);
  font-style: italic;
}

.value-string {
  color: var(--el-color-success);
}

.value-number {
  color: var(--el-color-warning);
}

.value-boolean {
  color: var(--el-color-primary);
  font-weight: bold;
}

.value-bigint {
  color: var(--el-color-warning);
}

.value-symbol {
  color: var(--el-color-info);
}

.value-date {
  color: var(--el-color-info);
  .el-icon {
    margin-right: 4px;
    vertical-align: middle;
  }
}

.value-regexp {
  color: var(--el-color-error);
}

.value-error {
  width: 100%;
  .error-stack {
    white-space: pre-wrap;
    word-break: break-all;
    font-size: 0.85em;
    max-height: 150px;
    overflow-y: auto;
    background-color: var(--el-color-error-light-9);
    border: 1px solid var(--el-color-error-light-7);
    padding: 5px;
    margin-top: 5px;
    border-radius: 4px;
  }
}

.value-function {
  .function-tag {
      color: var(--el-text-color-secondary);
      font-style: italic;
      margin-right: 5px;
  }
  .function-source-collapse {
    margin-top: 5px;
    border: 1px solid var(--el-border-color-lighter);
    border-radius: 4px;
    :deep(.el-collapse-item__header) {
        font-size: 0.9em;
        height: 30px;
        line-height: 30px;
        background-color: var(--el-fill-color-lighter);
    }
    :deep(.el-collapse-item__content) {
        padding: 5px;
    }
  }
  .function-source {
    white-space: pre-wrap;
    word-break: break-all;
    font-size: 0.85em;
    max-height: 200px;
    overflow: auto;
    background-color: var(--el-fill-color-light);
    padding: 8px;
    border-radius: 3px;
  }
}

.collection-summary {
    color: var(--el-text-color-secondary);
    font-style: italic;
    margin-right: 5px;
}

.collection-collapse {
    margin-top: 5px;
    border: 1px solid var(--el-border-color-lighter);
    border-radius: 4px;
    :deep(.el-collapse-item__header) {
        font-size: 0.9em;
        height: 30px;
        line-height: 30px;
        background-color: var(--el-fill-color-lighter);
    }
    :deep(.el-collapse-item__content) {
        padding: 8px;
        max-height: 250px; /* Limit height for large collections */
        overflow-y: auto;
    }
}

.map-entry,
.object-entry,
.set-value,
.array-item {
  display: flex;
  margin-bottom: 4px;
  padding-left: 10px; /* Indent items */
  align-items: flex-start; /* Align items at the start */
}

.map-key,
.object-key,
.array-index {
  flex-shrink: 0;
  margin-right: 5px;
  color: var(--el-text-color-secondary);
  font-weight: bold;
}

.map-separator {
    margin: 0 5px;
}

.map-value,
.object-value,
.array-value {
  flex-grow: 1;
  min-width: 0; /* Allow value display to shrink */
}

.limit-indicator {
    font-size: 0.8em;
    color: var(--el-text-color-disabled);
    margin-top: 5px;
    text-align: center;
}

.value-unknown {
  color: var(--el-text-color-placeholder);
  font-style: italic;
}

/* --- ADD Styles for Binary Data --- */
.value-binary {
  display: inline-flex; // Keep parts on one line if possible
  align-items: baseline;
  gap: 6px;
  font-style: italic;
}

.binary-type {
  font-weight: 600;
  color: var(--el-color-info); // Example color
}

.binary-size {
  color: var(--el-text-color-secondary);
  font-size: 0.9em;
}

.binary-preview {
  margin-left: 8px;
  color: var(--el-color-success);
  font-family: monospace;
  font-size: 0.9em;
}

/* Styles for the standard error block */
.standard-error {
  .error-name {
    font-weight: bold;
    color: var(--el-color-error);
    margin-right: 5px;
  }
  .error-message {
    /* Style as needed */
  }
  .error-stack {
    margin-top: 5px;
    font-size: 0.85em;
    color: var(--el-text-color-secondary);
    white-space: pre-wrap;
    word-break: break-all;
    background-color: var(--el-fill-color-lighter);
    padding: 4px 8px;
    border-radius: 4px;
    max-height: 150px; // Limit stack trace height
    overflow-y: auto;
  }
  .error-cause {
    margin-top: 8px;
    padding-left: 15px;
    border-left: 2px solid var(--el-border-color);
    .cause-label {
      font-weight: bold;
      font-size: 0.9em;
      color: var(--el-text-color-secondary);
      display: block;
      margin-bottom: 4px;
    }
  }
}

/* Styles for the special error block (using el-alert) */
.special-error {
  .error-stack { /* Style stack trace within el-alert if needed */
      margin-top: 5px;
      font-size: 0.85em;
      color: var(--el-text-color-secondary);
      white-space: pre-wrap;
      word-break: break-all;
      background-color: var(--el-fill-color-lighter);
      padding: 4px 8px;
      border-radius: 4px;
      max-height: 150px;
      overflow-y: auto;
  }
}
</style> 